package com.andy.servlet;


import com.andy.pojo.Handler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Component
public class DemoServlet extends HttpServlet {
    private List<Handler> handlerMapping = new ArrayList<>();

    public Map<String, Object> getSinglotObjects() {
        return singlotObjects;
    }

    public static void setSinglotObjects(Map<String, Object> singlotObjects) {
        DemoServlet.singlotObjects = singlotObjects;
    }

    public static Map<String, Object> singlotObjects;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String requestURI = req.getRequestURI();
        Handler handler = getHandler(requestURI);

        if (handler==null){
            resp.getWriter().write("404 not find");
            return;
        }


        System.out.println(requestURI);

        //找到之前存入的参数位置排序
        Map<String, Integer> parameterMap = handler.getParameterMap();


        int size = parameterMap.size();

        Object[] args = new Object[size];

        //拿到请求带的值
        Map<String, String[]> parameterMap1 = req.getParameterMap();
        //遍历所有拿到的参数集合
        for (Map.Entry<String, String[]> stringEntry : parameterMap1.entrySet()) {
            //将同名称的参数用,连接
            String value = StringUtils.join(stringEntry.getValue(), ",");
            //如果我们之前封装的handler的参数顺序中没有传入的参数名则继续找下一个参数
            if (!handler.getParameterMap().containsKey(stringEntry.getKey())){continue;}
            //通过传入的参数名称从handler里获取参数位置
            Integer integer = handler.getParameterMap().get(stringEntry.getKey());


            //将参数填充到数组的对应位置，等会反射调用方法要传入该参数
            args[integer] = value;
        }

        for (Map.Entry<String, Integer> stringIntegerEntry : parameterMap.entrySet()) {
            if (stringIntegerEntry.getKey().equalsIgnoreCase("HttpServletRequest")){
                Integer value = stringIntegerEntry.getValue();
                args[value] = req;
            }
            if (stringIntegerEntry.getKey().equalsIgnoreCase("HttpServletResponse")){

                Integer value = stringIntegerEntry.getValue();
                args[value] = resp;
            }
        }


        try {
            //反射调用方法
            handler.getMethod().invoke(handler.getObject(),args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }


    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        initHandlerMap();
        System.out.println("initHandlerMap");
    }

    private Handler getHandler(String url) {
        for (Handler handler : handlerMapping) {
            Matcher matcher = handler.getUrl().matcher(url);
            if (matcher.matches()){
                return handler;
            }
        }
        return null;
    }

    private void initHandlerMap() {
        for (Map.Entry<String, Object> entry : singlotObjects.entrySet()) {
            Object object = entry.getValue();
            Class<?> aClass = object.getClass();
            Method[] methods = aClass.getMethods();

            String[] classPath=null;
            String[] methodPath;

            String classPathStr="";

            //遍历这个类的所有方法
            for (Method method : methods) {
                boolean annotationPresent = method.isAnnotationPresent(RequestMapping.class);
                //如果方法含有RequestMapping注解
                if (annotationPresent){

                    RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
                    //取出类上的MyRequestMapping注解值
                    if (annotation!=null){
                        classPath = annotation.value();
                    }

                    RequestMapping annotation1 = method.getAnnotation(RequestMapping.class);

                    methodPath = annotation1.value();

                    if (classPath!=null){
                        classPathStr = classPath[0];
                    }


                    //类上的注解和方法上注解混合作用后的url
                    String url = classPathStr + methodPath[0] ;

                    Handler handler = new Handler(object,method, Pattern.compile(url));
                    Parameter[] parameters = method.getParameters();

                    //填充参数顺序
                    for (int i = 0; i < parameters.length; i++) {
                        if((parameters[i].getType()==HttpServletRequest.class) || (parameters[i].getType()==HttpServletResponse.class)){
                            handler.getParameterMap().put(parameters[i].getType().getSimpleName(),i);
                        }else{
                            handler.getParameterMap().put(parameters[i].getName(),i);
                        }
                    }

                    handlerMapping.add(handler);
                }
            }
        }
    }
}
